package com.isyscore.os.metadata.service.impl;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.isyscore.os.metadata.enums.MetricGraphType;
import com.isyscore.os.metadata.model.dto.GraphEdgeDTO;
import com.isyscore.os.metadata.model.dto.GraphNodeDTO;
import com.isyscore.os.metadata.model.dto.MetricGraphDTO;
import com.isyscore.os.metadata.model.entity.Datamodel;
import com.isyscore.os.metadata.model.entity.DatamodelColumn;
import com.isyscore.os.metadata.model.entity.Metric;
import com.isyscore.os.metadata.model.entity.MetricMeasure;
import com.isyscore.os.metadata.utils.SqlUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

import static com.isyscore.os.metadata.constant.CommonConstant.METRIC_PATH_SPLITTER;


@Service
public class MetricGraphService {

    @Autowired
    private MetricService metricService;

    @Autowired
    private DatamodelService datamodelService;

    @Autowired
    private DatamodelColumnService dataModelColumnService;

    @Autowired
    private SqlStatementService sqlStatementService;

    @Autowired
    private MetricMeasureService metricMeasureService;

    /**
     * 获取特定指标的关系图信息
     */
    public MetricGraphDTO getMetricGrath(Long metricId) {
        Metric metric = metricService.getFullMetricInfoById(metricId);
        Datamodel datamodel = datamodelService.getDatamodelById(metric.getDatamodelRefId());
        List<GraphNodeDTO> nodes = Lists.newArrayList();
        List<GraphEdgeDTO> edges = Lists.newArrayList();
        parseDatamodelAndMeasureGraph(datamodel, nodes, edges);
        List<Metric> rootMetrics = Lists.newArrayList(metricService.getRootMetricOfExtendMetric(metric));
        parseMeasureAndRootMetricGraph(rootMetrics, nodes, edges);
        for (Metric rootMetric : rootMetrics) {
            parseExtendMetricGraph(rootMetric, nodes, edges);
        }
        MetricGraphDTO metricGraphDto = new MetricGraphDTO();
        metricGraphDto.setEdges(edges);
        metricGraphDto.setNodes(nodes);
        return metricGraphDto;
    }

    /**
     * 获取特定模型下所有指标的关系图
     */
    public MetricGraphDTO getDatamodelGraph(Datamodel datamodel) {
        List<GraphNodeDTO> nodes = Lists.newArrayList();
        List<GraphEdgeDTO> edges = Lists.newArrayList();
        parseDatamodelAndMeasureGraph(datamodel, nodes, edges);
        List<Metric> rootMetrics = metricService.getAllRootMetricByDatamodel(datamodel.getId());
        parseMeasureAndRootMetricGraph(rootMetrics, nodes, edges);
        for (Metric rootMetric : rootMetrics) {
            parseExtendMetricGraph(rootMetric, nodes, edges);
        }
        MetricGraphDTO metricGraphDto = new MetricGraphDTO();
        metricGraphDto.setEdges(edges);
        metricGraphDto.setNodes(nodes);
        return metricGraphDto;
    }

    /**
     * 解析数据模型及所属度量的关系数据
     */
    public void parseDatamodelAndMeasureGraph(Datamodel datamodel, List<GraphNodeDTO> nodes, List<GraphEdgeDTO> edges) {
        String sql = sqlStatementService.getSqlById(datamodel.getSqlRefId());
        List<String> tables = SqlUtil.getSqlTableNames(sql);
        for (String table : tables) {
            String tableNodeId = table + "_" + System.currentTimeMillis();
            GraphNodeDTO datamodelNode = new GraphNodeDTO();
            datamodelNode.setId(tableNodeId);
            datamodelNode.setLabel(table);
            datamodelNode.setType(MetricGraphType.table.name());
            nodes.add(datamodelNode);
            //表 =》模型
            GraphEdgeDTO edge = new GraphEdgeDTO();
            //edge.setRelation("组成");
            edge.setSourceId(tableNodeId);
            edge.setTargetId(datamodel.getId().toString());
            edges.add(edge);
        }
        GraphNodeDTO datamodelNode = new GraphNodeDTO();
        datamodelNode.setId(datamodel.getId().toString());
        datamodelNode.setLabel(datamodel.getName());
        datamodelNode.setType(MetricGraphType.datamodel.name());
        datamodelNode.setDescription(datamodel.getDescription());
        nodes.add(datamodelNode);
        //添加度量值作为节点
        List<DatamodelColumn> columns = dataModelColumnService.getColumnsByDataModelId(datamodel.getId());
        for (DatamodelColumn column : columns) {
            if (column.getColType() == 2) {
                String measureNodeId = column.getColName() + "_measure";
                //度量值的节点
                GraphNodeDTO measureNode = new GraphNodeDTO();
                measureNode.setLabel(column.getColLabel());
                measureNode.setType(MetricGraphType.measure.name());
                measureNode.setId(measureNodeId);
                nodes.add(measureNode);
                //模型=》度量
                GraphEdgeDTO edge = new GraphEdgeDTO();
                edge.setRelation("度量");
                edge.setSourceId(datamodel.getId().toString());
                edge.setTargetId(measureNodeId);
                edges.add(edge);
            }
        }
    }

    /**
     * 解析度量和指标间的关系数据
     */
    public void parseMeasureAndRootMetricGraph(List<Metric> rootMetrics, List<GraphNodeDTO> nodes, List<GraphEdgeDTO> edges) {
        for (Metric metric : rootMetrics) {
            GraphNodeDTO measureNode = new GraphNodeDTO();
            measureNode.setId(metric.getId().toString());
            measureNode.setType(MetricGraphType.metric.name());
            measureNode.setLabel(metric.getName());
            nodes.add(measureNode);
            //度量=》指标
            List<MetricMeasure> measures = metricMeasureService.getMeasuresByMetricId(metric.getId());

            for (MetricMeasure measure : measures) {
                String measureNodeId = measure.getMeasureColName() + "_measure";
                GraphEdgeDTO edge = new GraphEdgeDTO();
                edge.setSourceId(measureNodeId);
                edge.setTargetId(metric.getId().toString());
                edges.add(edge);
            }
        }
    }

    /**
     * 构建从某个根指标派生出的所有指标的继承关系
     */
    public void parseExtendMetricGraph(Metric rootMetric, List<GraphNodeDTO> nodes, List<GraphEdgeDTO> edges) {
        Set<String> handledNodes = Sets.newHashSet();
        Set<String> handledEdges = Sets.newHashSet();
        handledNodes.add(rootMetric.getId().toString());
        //查询该根指标的所有派生指标
        List<Metric> children = metricService.getExtendMetricsByRoot(rootMetric.getId());
        for (Metric childMetric : children) {
            String[] codes = childMetric.getExtendPath().split(METRIC_PATH_SPLITTER);
            for (int i = 0; i < codes.length; i++) {
                String sourceCode = codes[i];
                if (!handledNodes.contains(sourceCode) && !Strings.isNullOrEmpty(sourceCode)) {
                    Metric aMetric = metricService.getFullMetricInfoById(Long.parseLong(sourceCode));
                    handledNodes.add(sourceCode);
                    GraphNodeDTO metricNode = new GraphNodeDTO();
                    metricNode.setId(sourceCode);
                    metricNode.setType(MetricGraphType.metric.name());
                    metricNode.setLabel(aMetric.getName());
                    nodes.add(metricNode);
                }
                //添加上级指标到下级指标的关系
                if (i + 1 < codes.length) {
                    String targetCode = codes[i + 1];
                    String edgeKey = sourceCode + ":" + targetCode;
                    //处理过的关系不再添加
                    if (!handledEdges.contains(edgeKey)) {
                        GraphEdgeDTO edge = new GraphEdgeDTO();
                        edge.setRelation("指标派生");
                        edge.setSourceId(sourceCode);
                        edge.setTargetId(targetCode);
                        edges.add(edge);
                        handledEdges.add(edgeKey);
                    }
                }
            }
        }
    }
}
